package com.game.core.frame
{
	import flash.events.Event;
	import flash.utils.getTimer;
	import com.game.core.GlobalInterface;

	public class FrameManager
	{
		public static const PRIORITY_HIGH : int = 1;
		public static const PRIORITY_LOW : int = 0;
		
		private var _lastFrameTime : int;
		private var _curFrameTime : int;
		private var _elapsedTime : int;
		
		private var _priorHighUpdatables : Vector.<IFrameUpdatable>;
		private var _priorLowUpdatables : Vector.<IFrameUpdatable>;
		private var _deleteUpdatables : Array;
		
		private static var _instance : FrameManager;
		public static function getInstance():FrameManager
		{
			if(!_instance)
				_instance = new FrameManager();
			return _instance;
		}
				
		public function FrameManager()
		{
			_priorHighUpdatables = new Vector.<IFrameUpdatable>;
			_priorLowUpdatables = new Vector.<IFrameUpdatable>;
			_deleteUpdatables = [];
		}
		
		public function run():void
		{
			GlobalInterface.stage.addEventListener(Event.ENTER_FRAME,onEnterFrame);
			_lastFrameTime = getTimer();
		}
		
		public function stop():void
		{
			GlobalInterface.stage.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
		}
		
		private function onEnterFrame(e:Event):void
		{
			_curFrameTime = getTimer();
			_elapsedTime = _curFrameTime - _lastFrameTime;
			try
			{
				update();
			}finally
			{
				_lastFrameTime = _curFrameTime;
			}
		}
		
		public function register(updatable : IFrameUpdatable,priority:int):void
		{
			var index : int = _deleteUpdatables.indexOf(updatable);
			if(index != -1)
				_deleteUpdatables.splice(index , 1);
			switch(priority)
			{
				case PRIORITY_HIGH:
					index = _priorHighUpdatables.indexOf(updatable);
					if(index > -1)return;
					updatable.notifyRegisterd();
					_priorHighUpdatables.push(updatable);
					break;
				case PRIORITY_LOW:
					index = _priorLowUpdatables.indexOf(updatable);
					if(index > -1)return;
					updatable.notifyRegisterd();
					_priorLowUpdatables.push(updatable);
					break;
			}
		}
		
		public function unRegister(updatable : IFrameUpdatable):void
		{
			var index : int = _deleteUpdatables.indexOf(updatable);
			if (index == -1)
			{
				_deleteUpdatables.push(updatable);
				updatable.notifyUnRegisterd();
			}
		}
		
		private function update():void
		{
			clearDeleteUpdatables();
			
			var i : int = _priorHighUpdatables.length;
			var frameUpdate : IFrameUpdatable;
			while(--i >= 0)
			{
				frameUpdate = _priorHighUpdatables[i];
				if(!frameUpdate && !frameUpdate.isRegister) continue;
				if(frameUpdate.checkUpdatable(_elapsedTime))
				{
					frameUpdate.update(frameUpdate.elapsedTimes);
				}
			}
			
			i = _priorLowUpdatables.length;
			while(--i >= 0)
			{
				frameUpdate = _priorLowUpdatables[i];
				if(!frameUpdate && !frameUpdate.isRegister) continue;
				if(frameUpdate.checkUpdatable(_elapsedTime))
				{
					frameUpdate.update(frameUpdate.elapsedTimes);
				}
			}
			
		}
		
		private function clearDeleteUpdatables():void
		{
			var i : int = _deleteUpdatables.length;
			while(--i >= 0)
			{
				var index : int = -1;
				var updatable : IFrameUpdatable = _deleteUpdatables[i];
				if(updatable == null)continue;
				
				index = _priorHighUpdatables.indexOf(updatable);
				if(index != -1)
				{
					_priorHighUpdatables.splice(index , 1);
					continue;
				}
				
				index = _priorLowUpdatables.indexOf(updatable);
				if(index != -1)
				{
					_priorLowUpdatables.splice(index , 1);
				}
			}
			_deleteUpdatables.length = 0;
		}
		
	}
}